#!/usr/bin/env node
/**
 * @description 去除相关国际化标识符,把代码还原到i18n之前,然后从0到1使用i18n的插件提取中文
 *
 * @example
 *  使用场景一: 先开发了东南亚的功能模块,然后需要把该功能模块从东南亚项目迁移到国内项目中
 *
 *  使用步骤，一共分为两步:
 *    第一步：参数配置
 *      - includes: 必填,要处理的文件夹或文件路径集合,例如 includes: [
 *          './src/views/operation/self-inspection',
 *          './src/views/operation/self-inspection/list.vue',
 *          './src/views/operation/self-inspection/setting/plan/hooks/useList.js',
 *        ]
 *      -必填 fileFormats: 必填,要处理的文件格式后缀名集合,例如 fileFormats: ['vue', 'js']
 *    第二步：执行命令
 *      node ./i18n.restore.js
 */
const fs = require("fs");
const path = require("path");

// 参数配置
const options = {
  // 要处理的文件夹或文件路径集合,例如 includes: ['./src/views/operation/self-inspection']
  includes: [],
  // 要处理的文件格式后缀名集合
  fileFormats: ["vue", "js"],
  // todo 是否使用原始字符串,从对应的json文件(locales/module/zh-cn/*.json)中获取中文文本
  isUseOriginStr: true,
};

/**
 * 获取文件夹中的所有文件，包括子文件夹中的文件
 * @param dirArr
 */
const getAllFilesInDir = (dirArr) => {
  // 检查dirArr是否为非空数组，如果不是或为空，则不执行后续代码
  if (!Array.isArray(dirArr) || dirArr?.length === 0) return;

  // 初始化结果数组，用于存储所有文件路径
  const result = [];
  // 遍历每个目录
  for (let i = 0; i < dirArr.length; i++) {
    const dir = dirArr[i];
    // 获取dir属性信息
    const stats = fs.statSync(dir);
    // 如果是文件，则将其路径添加到结果数组中,并跳出本次循环
    if (stats.isFile()) {
      result.push(dir);
      continue;
    }

    // 如果不是文件，则该目录下的所有文件，并同步返回文件列表
    const files = fs.readdirSync(dir);
    // 遍历每个文件或子目录
    files.forEach((file) => {
      // 拼接文件或子目录的完整路径
      const filePath = path.join(dir, file);
      // 获取文件或子目录的属性信息
      const stats = fs.statSync(filePath);
      // 如果是文件，则将其路径添加到结果数组中
      if (stats.isFile()) {
        result.push(filePath);
      } else if (stats.isDirectory()) {
        // 如果是子目录，则递归调用读取子文件夹中的文件，并将结果合并到结果数组中
        const subFiles = getAllFilesInDir([filePath]);
        result.push(...subFiles);
      }
    });
  }

  return result;
};

/**
 * todo 根据文件路径和要替换的key获取原始文本
 * @param fileKey 文件路径
 * @param strKey 要替换的key
 */
const getOriginStrByKey = (fileKey, strKey) => {
  return strKey;

  const fileKeyPath = `./locales/module/zh-cn/${fileKey}.json`;
  try {
    const originStr = fs
      .readFileSync(fileKeyPath, "utf8")
      .match(new RegExp(`"${strKey}":\\s*"([^"]*)"`, "g"))?.[0]
      ?.split(":")?.[1]
      ?.replace(" ", "")
      ?.replaceAll('"', "");

    return originStr || strKey;
  } catch (e) {
    console.log(e);
    return strKey;
  }
};

/**
 * 处理vue文件中html标签内的 {{ $t('operation.导入完成') }}
 * @param data 要处理的文件内容
 */
const handleVueFileHtmlLabelInner = (data) => {
  const regex = /\{\{\s+\$t\((\s*)'([^']*)'(\s*)\)\s+\}\}/g;
  let newData = data.replace(regex, (match, p1) => {
    match = match.replace(/[\n\r\t\s]/g, "");
    const fileKey = match.split(".")[0].replace("{{$t('", "");

    const chineseText = match.split(".").pop().replace("')}}", "");
    return getOriginStrByKey(fileKey, chineseText);
  });

  return newData;
};

/**
 * 处理vue文件中html标签的属性值 :title="$t('operation.导入完成')"
 * @param data 要处理的文件内容
 */
const handleVueFileHtmlLableProperty = (data) => {
  const regex = /:([\w-]+)="(\s*)\$t\((\s*)'([^']*)'(\s*)\)(\s*)"/g;
  let newData = data.replace(regex, (match, p1) => {
    match = match.replace(/[\n\r\t\s]/g, "");
    const tempArr = match.split("$t");
    const equalLeft = tempArr[0].replace(":", "");
    let equalRight = tempArr[1].split(".").pop();
    if (equalRight.endsWith("')\""))
      equalRight = equalRight.substring(0, equalRight.length - 3);
    const chineseText = equalLeft + equalRight + '"';

    const fileKey = tempArr[1]
      .split(".")[0]
      .replaceAll("$t", "")
      .replaceAll("('", "");
    return getOriginStrByKey(fileKey, chineseText);
  });

  return newData;
};

/**
 * 处理js文件中的 $t('operation.导入完成')
 * @param data 要处理的文件内容
 */
const handleJsFile = (data) => {
  const regex = /\$t\((\s*)'([^']*)'(\s*)\)/g;
  let newData = data.replace(regex, (match, p1) => {
    match = match.replace(/[\n\r\t\s]/g, "");
    const fileKey = match.split(".")[0].replace("$t('", "");
    match = match.split(".").pop();
    const chineseText = match.replace("')", "");

    return `'${getOriginStrByKey(fileKey, chineseText)}'`;
  });

  return newData;
};

/**
 * 处理$t-slot标签
 *    $t('operation.{errMsg},导入失败', { errMsg: errMsg })
 *    $t('base.确定将_{slot1}_数据删除?', { slot1: this.regionForm.name })
 * @param data 要处理的文件内容
 */
const getSlotKeys = (str) => {
  const regex = /\{([^}]+)\}/g;
  let match;
  const slotKeys = [];
  while ((match = regex.exec(str)) != null) {
    slotKeys.push(match[1]);
  }

  return slotKeys;
};
const getSlotValues = (str) => {
  let slotStr = str.match(/,\s*\{([^}]+)\}/g)?.[0];
  const regex = /:\s*(.*?)(?=\s*,\s*\w+\s*:|$)/g;
  const slotValues = [];
  let match;
  while ((match = regex.exec(slotStr)) != null) {
    slotValues.push(match[1]);
  }

  return slotValues;
};
const handleSlot = (data) => {
  const regex = /\$t\((\s*)'([^']*)'(\s*),\s*\{(\s*)([^}]*)(\s*)\}(\s*)\)/g;
  let newData = data.replace(regex, (match, p1) => {
    match = match.replace(/([\n\r\t]*)(\s{2,})/g, "");
    const result = match.split("',");
    const key = handleJsFile(result[0] + "')").replaceAll("'", "");
    const slotKeys = getSlotKeys(key);
    const slotValues = getSlotValues(match);
    let chineseText = key;
    for (let i = 0; i < slotKeys.length; i++) {
      const slotKey = slotKeys[i];
      let slotValue = slotValues[i];
      if (slotValue?.endsWith(",}"))
        slotValue = slotValue.substring(0, slotValue.length - 2);
      if (slotValue?.endsWith("}"))
        slotValue = slotValue.substring(0, slotValue.length - 1);

      chineseText = chineseText.replace(`{${slotKey}}`, `\${ ${slotValue}}`);
    }
    return `\`${chineseText}\``;
  });

  return newData;
};

/**
 * 替换所有文件的国际化标识符
 *
 * @param includes 要处理的文件夹或文件路径集合
 * @param fileFormats 要处理的文件格式后缀名集合
 */
const handleReplaceRelated = (option) => {
  if (!option) {
    console.log("参数配置不可为空,请检查");
    return;
  }
  const { includes, fileFormats } = option;
  if (!Array.isArray(includes) || includes?.length === 0) {
    console.log("includes参数配置不可为空,请检查");
    return;
  }
  if (!Array.isArray(fileFormats) || fileFormats?.length === 0) {
    console.log("fileFormats参数配置不可为空,请检查");
    return;
  }

  // 获取所有文件路径
  const filePaths = getAllFilesInDir(includes);
  console.log("要处理的所有文件allFilePaths", filePaths?.length, filePaths);

  filePaths?.forEach((file) => {
    // 获取文件夹后缀名
    const fileExt = path.extname(file);
    // 如果不是指定格式的文件，则跳过
    if (fileExt && !fileFormats.includes(fileExt.substring(1))) return;

    /*
			使用fs模块的readFile方法异步读取文件内容
			参数1: file，要读取的文件路径
			参数2: 'utf8'，指定读取文件时使用的字符编码格式为utf8
			回调函数: (readErr, data) => {...}
				readErr - 读取文件时发生的错误，如果没有错误则为null
				data - 读取到的文件内容，如果发生错误则可能为undefined
		 */
    fs.readFile(file, "utf8", (readErr, data) => {
      // 检查读取文件时是否发生了错误
      if (readErr) {
        // 如果发生错误，打印错误信息到控制台
        console.error(readErr);
        // 终止函数执行，不进行后续操作
        return;
      }
      // 定义正则表达式来匹配国际化标识符，提取其中的中文内容
      // 1 处理vue文件中html标签内的{{ $t('operation.导入完成') }}
      let newData = handleVueFileHtmlLabelInner(data);
      // 2 处理vue文件中html标签的属性值 :title="$t('operation.导入完成')"
      newData = handleVueFileHtmlLableProperty(newData);
      // 3 处理js文件中的$t('operation.导入完成')
      newData = handleJsFile(newData);
      // 4 处理$t-slot标签
      newData = handleSlot(newData);

      /*
				使用fs模块的writeFile方法异步地写入文件
				参数1: file，要写入的文件路径
				参数2: newData，要写入文件的新数据
				参数3: 'utf8'，指定文件编码格式为utf8
				回调函数: writeErr => {...}
					用于处理写入文件时发生的错误
			*/
      fs.writeFile(file, newData, "utf8", (writeErr) => {
        // 检查写入文件过程中是否有错误发生
        if (writeErr) {
          // 如果有错误，输出错误信息到控制台
          console.error(writeErr);
          // 结束当前函数执行，不进行后续操作
          return;
        }
        // 如果没有错误，输出成功消息到控制台
        console.log(`在文件 ${file} 中去除国际化标识符成功`);
      });
    });
  });
};

// 导出函数
export default handleReplaceRelated;
